package com.lighting.common.exception;

import com.lighting.common.core.constants.ErrorCode;
import com.lighting.common.core.vo.BusinessException;
import com.lighting.common.core.vo.Result;
import com.lighting.common.core.vo.RpcException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.NoHandlerFoundException;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.sql.SQLIntegrityConstraintViolationException;

@Slf4j
public abstract class AbstractExceptionHandler {

    @Value("${spring.profiles.active:}")
    private String active;

    @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
    public ResponseEntity<?> handlerException(HttpRequestMethodNotSupportedException e) {
        log.error(e.getMessage(), e);
        return ResponseEntity.status(HttpStatus.OK).body(Result.fail(e.getMessage()));
    }

    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    public ResponseEntity<?> handlerException(MissingServletRequestParameterException e) {
        log.error(e.getMessage(), e);
        return ResponseEntity.status(HttpStatus.OK).body(Result.fail(ErrorCode.BAD_REQUEST, e.getMessage()));
    }

    @ExceptionHandler(value = BusinessException.class)
    public ResponseEntity<?> handlerException(BusinessException e) {
        if (e.getCause() != null) {
            return this.handlerException((BusinessException) e.getCause());
        }
        return ResponseEntity.status(HttpStatus.OK).body(Result.fail(e.getCode(), e.getMessage()));
    }

    @ExceptionHandler(value = RpcException.class)
    public ResponseEntity<?> handlerDubboException(RpcException e) {
        return ResponseEntity.status(HttpStatus.OK).body(Result.fail(e.getCode(), e.getMessage()));
    }

    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public ResponseEntity<?> handlerMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        String message = bindingResult.getFieldErrors().get(0).getDefaultMessage();
        return ResponseEntity.status(HttpStatus.OK).body(Result.fail(ErrorCode.BAD_REQUEST, message));
    }

    @ExceptionHandler(SQLIntegrityConstraintViolationException.class)
    public ResponseEntity<?> handleSQLIntegrityConstraintViolationException(SQLIntegrityConstraintViolationException e) {
        log.error(e.getMessage(), e);
        return ResponseEntity.status(HttpStatus.OK).body(Result.fail(ErrorCode.BUSINESS_ERROR, "SQL完整性约束异常(重复添加已存在的数据)"));
    }

    @ExceptionHandler(NoHandlerFoundException.class)
    public ResponseEntity<?> handleNoHandlerFoundException(NoHandlerFoundException e) {
        log.error(e.getMessage(), e);
        return ResponseEntity.status(HttpStatus.OK).body(Result.fail(ErrorCode.NOT_FOUND));
    }

    @ExceptionHandler(value = Throwable.class)
    public ResponseEntity<?> handlerThrowable(Throwable e) {
        if (RuntimeException.class.equals(e.getClass()) && e.getCause() == null) {
            return ResponseEntity.status(HttpStatus.OK).body(Result.fail(ErrorCode.BUSINESS_ERROR, e.getMessage()));
        }
        log.error(e.getMessage(), e);
        return ResponseEntity.status(HttpStatus.OK).body(Result.fail(ErrorCode.EXCEPTION));
    }

    protected String getStackTrace(Throwable e) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        e.printStackTrace(pw);
        String s = sw.toString();
        pw.close();
        return "\r\n" + s + "\r\n";
    }
}
